// region 扩展方法

if (!Array.prototype.includes) {
    Array.prototype.includes = function (searchElement, fromIndex) {
        if (fromIndex == undefined) {
            fromIndex = 0;
        }

        for (let i = fromIndex; i < this.length; i++) {
            if (this[i] == searchElement) {
                return true;
            }
        }
        return false;
    };
}

if (!Array.prototype.some) {
    Array.prototype.some = function (callback) {
        if (typeof callback !== 'function') {
            throw new TypeError(callback + ' is not a function');
        }

        for (let i = 0; i < this.length; i++) {
            if (callback(this[i], i, this)) {
                return true;
            }
        }
        return false;
    };
}

if (!Array.prototype.find) {
    Array.prototype.find = function (callback) {
        if (typeof callback !== 'function') {
            throw new TypeError(callback + ' is not a function');
        }

        let result;
        const arr = this;
        for (let i = 0; i < arr.length; i++) {
            if (callback(arr[i])) {
                result = arr[i];
                break;
            }
        }
        return result;
    };
}

if (!Array.prototype.filter) {
    Array.prototype.filter = function (callback) {
        if (typeof callback !== 'function') {
            throw new TypeError(callback + ' is not a function');
        }

        const result = [];
        const arr = this;
        for (let i = 0; i < arr.length; i++) {
            if (callback(arr[i], i, arr)) {
                result.push(arr[i]);
            }
        }
        return result;
    };
}

if (!Array.prototype.map) {
    Array.prototype.map = function (callback) {
        if (typeof callback !== 'function') {
            throw new TypeError(callback + ' is not a function');
        }

        const result = [];
        const arr = this;
        for (let i = 0; i < arr.length; i++) {
            result.push(callback(arr[i], i, arr));
        }
        return result;
    };
}

if (!Array.prototype.isEmpty) {
    Array.prototype.isEmpty = function () {
        return this.length == 0;
    };
}

if (!String.prototype.padStart) {
    String.prototype.padStart = function (len, padStr) {
        let str = this
        while (str.length < len) {
            str = padStr + str
        }
        return str
    }
}

if (!String.prototype.includes) {
    String.prototype.includes = function(search, start) {
        if (typeof start !== 'number') {
            start = 0;
        }
        if (start + search.length > this.length) {
            return false;
        }
        return this.indexOf(search, start) !== -1;
    };
}

if (!Object.prototype.keys) {
    Object.prototype.keys = function (obj) {
        const keyList = []
        for (let key in obj) {
            keyList.push(key);
        }
        return keyList;
    }
}

// endregion

const GeneralUtils = {};

/**
 * 是否为空
 * @param obj
 * @returns {boolean}
 */
GeneralUtils.isEmpty = (obj) => {
    if (obj == null) {
        return true;
    }
    const type = typeof obj;
    switch (type) {
        case 'string':
            return obj.length == 0;
        case 'object':
            if (!Array.isArray(obj)) {
                return Object.keys(obj).length == 0
            }
            return obj.length == 0
        case "number":
            return isNaN(obj);
        default:
            break;
    }
    return false;
};

/**
 * 是否非空
 * @param obj
 * @returns {boolean}
 */
GeneralUtils.isNotEmpty = (value) => {
    return !GeneralUtils.isEmpty(value);
};

/**
 * 是否为空字符
 * @param {string} obj
 * @returns {boolean}
 */
GeneralUtils.isBlank = (obj) => {
    if (obj == null) {
        return true;
    }
    if (typeof obj == 'string') {
        return obj.trim() == '' || obj.trim() == 'null';
    }
    return false;
};

/**
 * 是否非空字符
 * @param {string} obj
 * @returns {boolean}
 */
GeneralUtils.isNotBlank = (obj) => {
    return !GeneralUtils.isBlank(obj);
};

/**
 * 格式化日期
 * @param date          默认当前时间
 * @param isNeedTime    是否需要追加时分秒
 * @param replaceSymbol 是否替换符号
 * @returns {string} yyyy-MM-dd | yyyy-MM-dd HH:mm:ss | yyyyMMdd | yyyyMMddHHmmss
 */
GeneralUtils.formatDate = (date, isNeedTime, replaceSymbol) => {
    if (!date) {
        date = new Date();
    } else {
        date = new Date(date);
    }
    const year = date.getFullYear();
    let month = (date.getMonth() + 1).toString();
    month = month.length > 1 ? month : '0' + month;
    let day = date.getDate().toString();
    day = day.length > 1 ? day : '0' + day;
    let hours = date.getHours().toString();
    hours = hours.length > 1 ? hours : '0' + hours;
    let minutes = date.getMinutes().toString();
    minutes = minutes.length > 1 ? minutes : '0' + minutes;
    let seconds = date.getSeconds().toString();
    seconds = seconds.length > 1 ? seconds : '0' + seconds;
    let dateStr = year + "-" + month + "-" + day;
    if (isNeedTime) {
        dateStr += " " + hours + ":" + minutes + ":" + seconds;
    }
    if (replaceSymbol) {
        dateStr = dateStr.replace(/[-: ]/g, '');
    }
    return dateStr;
};


/**
 * 获取当天时间字符串
 * @returns {string} yyyy-MM-dd
 */
GeneralUtils.getCurrentDateStr = () => {
    return GeneralUtils.formatDate(new Date(), false, false);
}

/**
 * 获取当天时间字符串
 * @returns {string} yyyy-MM-dd
 */
GeneralUtils.getCurrentTimeStr = () => {
    return GeneralUtils.formatDate(new Date(), true, false);
}


/**
 * 获取日期范围字符串数组 [yyyyMMdd...]
 * @param startDate
 * @param endDate
 * @param replaceSymbol 字符串是否替换'-'符号
 * @returns {*[]}
 */
GeneralUtils.getDateRange = (startDate, endDate, replaceSymbol) => {
    startDate = new Date(startDate);
    endDate = new Date(endDate);
    let dateRangeList = [];
    while (startDate <= endDate) {
        dateRangeList.push(GeneralUtils.formatDate(startDate, false, replaceSymbol));
        startDate.setDate(startDate.getDate() + 1);
    }
    return dateRangeList;
}

/**
 * 获取最近x天的日期字符串数组
 * @param dayNum
 * @returns {*[]}
 */
GeneralUtils.getLastNDays = (dayNum) => {
    const today = new Date();
    today.setHours(0, 0, 0, 0);
    let days = [];
    // 循环dayNum次，每次向前推一天
    for (let i = 0; i < dayNum; i++) {
        // 向前推i天
        today.setDate(today.getDate() - 1);
        days.push(GeneralUtils.formatDate(today, false, true));
    }
    return days;
}

/**
 * 生成唯一ID（32位)
 */
GeneralUtils.uuid = () => {
    return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, (s) => {
        const random = Math.random() * 16 | 0;
        return (s == 'x' ? random : random & 0x3 | 0x8).toString(16);
    });
}

/**
 * 生成链路ID（30位：16位uuid + yyyyMMddHHmmss)
 */
GeneralUtils.buildTraceId = () => {
    return 'xxxxxxxxxxxx4xxx'.replace(/[xy]/g, (s) => {
        const random = Math.random() * 16 | 0;
        return (s == 'x' ? random : random & 0x3 | 0x8).toString(16);
    }) + "-" + GeneralUtils.formatDate(new Date(), true, true);
}

/**
 * 深克隆对象
 * @param {object} data
 * @returns {string|*}
 */
GeneralUtils.cloneDeep = (data) => {
    if (GeneralUtils.isEmpty(data)) {
        return data;
    }
    return JSON.parse(JSON.stringify(data));
}

/**
 * 获取随机数
 * @param min
 * @param max
 * @returns {number}
 */
GeneralUtils.getRandomInt = (min, max) => {
    min = Math.ceil(min);
    max = Math.floor(max);
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

module.exports = GeneralUtils;